// sccetest.cpp : Defines the entry point for the application.
//

#include "stdafx.h"

#define DWIN32

#include "casmcard.h" 
#include <string.h>
#include <stdio.h>
#include <memory.h>

//#define PRINT_MESSAGE

//#undef UNICODE
//#undef _UNICODE
//#undef _UNICODE_

#define MAX_READER_NUMBER	10
#define MAX_RECV_BUFFER_SIZE 4096

SCARDCONTEXT ScardContext;
DWORD	ReaderNameLength;
DWORD	ReadersNum = 0;
LPTSTR  ReaderName;
SCARD_READERSTATE ScardReaderState[MAX_READER_NUMBER];
SCARDHANDLE ScardHandle[MAX_READER_NUMBER];
SCARD_IO_REQUEST ScardIoRequest[MAX_READER_NUMBER];
DWORD  ScardProtocol[MAX_READER_NUMBER];
int CurrentReader;

BYTE SendBuffer[256+5];
DWORD SendLength;
BYTE RecvBuffer[MAX_RECV_BUFFER_SIZE];
DWORD RecvLength;

BYTE GetChallengeCommand[] = {0xCA, 0x86, 0x00, 0x00, 0x08};
BYTE ReadBinaryCommand[] = {0xCA, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00};
BYTE WriteBinaryCommand[] = {0xCA, 0xD0, 0x00, 0x00, 0x00};

int MessageLevel;

#define NO_MESSAGE	0
#define SHOW_LOOP	1
#define SHOW_ACTION	2
#define SHOW_DATA	3

void PrintBuffer(const char* msg, BYTE* buf, DWORD len)
{
	DWORD i;

	printf(msg);
	for(i = 0; i < len; ++i)
	{
		printf("%02X ", buf[i]);
	}
	printf("\n");
}

int ReadBinary(short int readlen)
{
	long result;
	short int t;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("ReadBinary %d byte(s)\n", readlen);
	}

	ScardIoRequest[CurrentReader].dwProtocol = ScardProtocol[CurrentReader];
    ScardIoRequest[CurrentReader].cbPciLength = sizeof(SCARD_IO_REQUEST);	   	
	
	RecvLength = MAX_RECV_BUFFER_SIZE;

	t = (readlen >> 8);

	ReadBinaryCommand[5] = t;
	ReadBinaryCommand[6] = readlen;

	if(MessageLevel >= SHOW_DATA)
	{
		PrintBuffer("	    Send : ", ReadBinaryCommand, sizeof(ReadBinaryCommand));
	}

	result = CasTransmit(ScardHandle[CurrentReader],
							&ScardIoRequest[CurrentReader],
							ReadBinaryCommand,
							sizeof(ReadBinaryCommand),
							&ScardIoRequest[CurrentReader],
							RecvBuffer,
							&RecvLength);

    if(result == SCARD_S_SUCCESS)
	{
		if(MessageLevel >= SHOW_DATA)
		{
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}
		return 1;
	}
	
	printf("ReadBinary : 0x%08x (%d)\n", result, result);

	return 0;	
}

// flag : 1 - use buf
//		  0 - don't use
int WriteBinary(short int writelen, BYTE* buf, int flag)
{
	long result;
	int i;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("WriteBinary %d byte(s)\n", writelen);
	}

	ScardIoRequest[CurrentReader].dwProtocol = ScardProtocol[CurrentReader];
    ScardIoRequest[CurrentReader].cbPciLength = sizeof(SCARD_IO_REQUEST);	
    	
	RecvLength = MAX_RECV_BUFFER_SIZE;

	memcpy(SendBuffer, WriteBinaryCommand, 4);

	SendBuffer[4] = writelen;

	if(flag)
	{
		memcpy((void*)(SendBuffer + 5), buf, writelen);
	}
	else
	{
		for(i = 0; i < writelen; ++i)
			SendBuffer[5+i] = i;	
	}

	SendLength = 5 + writelen;

	if(MessageLevel >= SHOW_DATA)
	{
		PrintBuffer("	    Send : ", SendBuffer, SendLength);
	}

	result = CasTransmit(ScardHandle[CurrentReader],
							&ScardIoRequest[CurrentReader],
							SendBuffer,
							SendLength,
							&ScardIoRequest[CurrentReader],
							RecvBuffer,
							&RecvLength);

    if(result == SCARD_S_SUCCESS)
	{

		if(MessageLevel >= SHOW_DATA)
		{
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}

		return 1;
	}	

	printf("WriteBinary : 0x%08X (%d)\n", result, result);

	return 0;		
}

int GetRandomNumber()
{
	long result;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("GetRandomNumber\n");
	}

	ScardIoRequest[CurrentReader].dwProtocol = ScardProtocol[CurrentReader];
    ScardIoRequest[CurrentReader].cbPciLength = sizeof(SCARD_IO_REQUEST);	
    	
	RecvLength = MAX_RECV_BUFFER_SIZE;

	if(MessageLevel >= SHOW_DATA)
	{
		PrintBuffer("	    Send : ", GetChallengeCommand, sizeof(GetChallengeCommand));
	}

	result = CasTransmit(ScardHandle[CurrentReader],
							&ScardIoRequest[CurrentReader],
							GetChallengeCommand,
							sizeof(GetChallengeCommand),
							&ScardIoRequest[CurrentReader],
							RecvBuffer,
							&RecvLength);

    if(result == SCARD_S_SUCCESS)
	{
		if(MessageLevel >= SHOW_DATA)
		{
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}
		
		return 1;
	}
	
	printf("GetRandomNumber : 0x%08X (%d)\n", result, result);

	return 0;
}

int Connect()
{
	long result;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("Connect\n");
	}

	result = CasConnect(	 ScardContext,
	                     ScardReaderState[CurrentReader].szReader,
	                     SCARD_SHARE_EXCLUSIVE,
	                     SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
	                     &ScardHandle[CurrentReader],
	                     &ScardProtocol[CurrentReader]);
	
	if(result == SCARD_S_SUCCESS)
	{
		if(MessageLevel >= SHOW_ACTION)
		{
			printf("Connect Success\n");
		}
		return 1;
	}
	
	printf("CasConnect Fail : %08X (%d)\n", result, result);
	
	return 0;
}

int Disconnect()
{
	long result;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("Disconnect\n");
	}

	result = CasDisconnect(ScardHandle[CurrentReader],
                                       SCARD_UNPOWER_CARD);
                                       
	if(result == SCARD_S_SUCCESS)
	{
		if(MessageLevel >= SHOW_ACTION)
		{
			printf("Disconnect Success\n");
		}
		return 1;
	}
	
	printf("CasDisconnect Fail : %08X\n", result);
                                       	
	return 0;
}


int Init()
{
	long result;
    int i;	
    LPTSTR readerName;


    result = CasEstablishContext(SCARD_SCOPE_SYSTEM,
                                 NULL,
                                 NULL,
                                 &ScardContext);

    if(result != SCARD_S_SUCCESS)
	{
        printf("CasEstablishContext Fail : %08X\n", result);
        return 0;
    }
    
    printf("CasEstablishContext Success\n");

	// Find out ReaderNameLength
    result = CasListReaders(ScardContext, NULL, NULL, &ReaderNameLength);

    if(result != SCARD_S_SUCCESS)
	{
		printf("CasListReadersA Fail : %08X\n", result);
		ReaderNameLength = 100;
        return 0;
    }
    
    printf("CasListReaders Success : %d\n", ReaderNameLength);

    // Allcoate Memory for ReaderName
    ReaderName = (LPTSTR)malloc(ReaderNameLength); //new char[ReaderNameLength];    

    // List Reader Name
    ReadersNum= 0;
    result = CasListReaders(ScardContext,
                              NULL,
                              ReaderName,
                              &ReaderNameLength);

    if(result == SCARD_S_SUCCESS)
	{

       readerName = ReaderName;

       while((*readerName != '\0') && (ReadersNum < MAX_READER_NUMBER))
	   {

          ScardReaderState[ReadersNum].szReader = (LPTSTR)readerName;
          ScardReaderState[ReadersNum].dwCurrentState = SCARD_STATE_UNAWARE;
          ++ReadersNum;
          //readerName += strlen(readerName) + 1;
          readerName += wcslen(readerName) + 1;
       }
    }
	else
	{

	   printf("CasListReadersA Fail : %08X\n", result);
       
      return 0;
    }
    
    printf("List  Readers : \n", result);
	for(i = 0; i < (int)ReadersNum; ++i)
	{
	
		wprintf(L"%d)%s\n", i, ScardReaderState[i].szReader);
	
	}

	return 1;
}


int Test_Part_1(int loop, int flag, int repeat)
{
	int i;

	printf("Test Part 1 - Power Action\n");
	printf("Start.........................\n");
	for(i = 0; i < loop; ++i)
	{
		if(!Connect())
		{
			printf("Test Part 1 - Power Action Fail - \n");
			printf("	<%d> Connect Fail : Loop = %d\n", repeat, loop+1);
			return 0;
		}

		if(!Disconnect())
		{
			printf("Test Part 1 - Power Action Fail - \n");
			printf("	<%d> Disconnect Fail : Loop = %d\n", repeat, loop+1);
			return 0;
		}

		if(flag)
		{
			printf("<%d> Part 1 loop = %d\n", repeat, i);
		}
	}
	printf("End.........................\n");
	printf("Test Part 1 -  Success\n");

	return 1;
}

int Test_Part_2(int loop, int flag, int repeat)
{
	int i, j;
	short int const lenarray[] = {1, 5, 128, 241, 242, 243, 249, 254, 255, 511, 1023};
	short int writelen;

	printf("Test Part 2 - Power Read Write Action\n");
	printf("Start.........................\n");
	for(i = 0; i < loop; ++i)
	{
		if(!Connect())
		{
			printf("Test Part 2 - Power Read Write Action Fail - \n");
			printf("	<%d> Connect Fail : Loop = %d\n", repeat, loop+1);
			return 0;
		}

		for(j = 0; j < 11; ++j)
		{

			writelen = lenarray[j] > 255 ? 255 : lenarray[j];
			if(!WriteBinary(writelen, NULL, 0))
			{
				printf("Test Part 2 - Power Read Write Action Fail - \n");
				printf("	<%d> WriteBinary(%d) Fail : Loop = %d\n", repeat, writelen, loop+1);
				return 0;
			}
			
			if(!ReadBinary(lenarray[j]))
			{
				printf("Test Part 2 - Power Read Write Action Fail - \n");
				printf("	<%d> ReadBinary(%d) Fail : Loop = %d\n", repeat, lenarray[j], loop+1);
				return 0;
			}
		}

		if(!Disconnect())
		{
			printf("Test Part 2 - Power Read Write Action Fail - \n");
			printf("	<%d> Disconnect Fail : Loop = %d\n", repeat, loop+1);
			return 0;
		}

		if(flag)
		{
			printf("<%d> Part 2 loop = %d\n", repeat, i);
		}
	}
	printf("End.........................\n");
	printf("Test Part 2 -  Success\n");

	return 1;
}


int Test_Part_3(int loop, int flag, int repeat)
{
	int i, j;
	short int const lenarray[] = {1, 5, 128, 241, 242, 243, 249, 254, 255, 511, 1023};
	short int writelen;

	printf("Test Part 3 - Read Write Action\n");
	printf("Start.........................\n");

	if(!Connect())
	{
		printf("Test Part 3 - Read Write Action Fail - \n");
		printf("	<%d> Connect Fail\n", repeat);
		return 0;
	}

	for(i = 0; i < loop; ++i)
	{
		for(j = 0; j < 11; ++j)
		{
			writelen = lenarray[j] > 255 ? 255 : lenarray[j];
			if(!WriteBinary(writelen, NULL, 0))
			{
				printf("Test Part 3 - Read Write Action Fail - \n");
				printf("	<%d> WriteBinary(%d) Fail : Loop = %d\n", repeat, writelen, loop+1);
				return 0;
			}
			
			if(!ReadBinary(lenarray[j]))
			{
				printf("Test Part 3 - Read Write Action Fail - \n");
				printf("	<%d> ReadBinary(%d) Fail : Loop = %d\n", repeat, lenarray[j], loop+1);
				return 0;
			}
		}

		if(flag)
		{
			printf("<%d> Part 3 loop = %d\n", repeat, i);
		}
	}

	if(!Disconnect())
	{
		printf("Test Part 3 - Read Write Action Fail - \n");
		printf("	<%d> Disconnect Fail\n", repeat);
		return 0;
	}

	printf("End.........................\n");
	printf("Test Part 3 -  Success\n");

	return 1;
}


int Test_SLE4442()
{
	long result;
	
	if(!Connect())
	{
		printf("Test_SLE4442 - Fail - \n");
		printf("	<%d> Connect Fail : Loop = %d\n");
		return 0;
	}

	RecvLength = 256;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("SLE4442 Read Main Memory %d byte(s)\n", RecvLength);
	}
	

	result = SLE4442_Read_Main_Memory(ScardHandle[CurrentReader],
							RecvBuffer,
							0,
							&RecvLength);

	if(result == SCARD_S_SUCCESS)
	{

		if(MessageLevel >= SHOW_DATA)
		{
			printf(     "       Recv Length = %d byte(s)\n", RecvLength);
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}

		
	}
	else
	{
		printf("SLE4442 Read Main Memory : 0x%08x (%d)\n", result, result);
	}

	if(!Disconnect())
	{
		printf("Test_SLE4442 - Fail - \n");
		printf("	<%d> Disconnect Fail\n");
		return 0;
	}

	return 1;	
}

int Test_SLE4428()
{
	long result;
	
	if(!Connect())
	{
		printf("Test_SLE4428 - Fail - \n");
		printf("	<%d> Connect Fail : Loop = %d\n");
		return 0;
	}

	RecvLength = 1024;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("SLE4428 Read Data Without Protect Bit %d byte(s)\n", RecvLength);
	}
	

	result = SLE4428_Read_Data_Without_Protect_Bit(ScardHandle[CurrentReader],
							RecvBuffer,
							0,
							&RecvLength);

	if(result == SCARD_S_SUCCESS)
	{

		if(MessageLevel >= SHOW_DATA)
		{
			printf(     "       Recv Length = %d byte(s)\n", RecvLength);
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}

		
	}
	else
	{
		printf("SLE4428 Read Data Without Protect Bit : 0x%08x (%d)\n", result, result);
	}
	
	if(!Disconnect())
	{
		printf("Test_SLE4428 - Fail - \n");
		printf("	<%d> Disconnect Fail\n");
		return 0;
	}

	return 1;
}


int Test_I2C_Read()
{
	long result;
	
	if(!Connect())
	{
		printf("Test_I2C_Read - Fail - \n");
		printf("	<%d> Connect Fail : Loop = %d\n");
		return 0;
	}

	// 1
	RecvLength = 256;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("I2C Read Memory (cmd=0xA1) %d byte(s) with Dummy=1, #ofAddr=2\n", RecvLength);
	}

	result = I2C_Read_Memory(ScardHandle[CurrentReader], 
					0xA1,
					0x00,
					RecvBuffer,
					&RecvLength,
					0x01,
					0x02);

	if(result == SCARD_S_SUCCESS)
	{

		if(MessageLevel >= SHOW_DATA)
		{
			printf(     "       Recv Length = %d byte(s)\n", RecvLength);
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}

	}
	else
	{
		printf("I2C Read Memory : 0x%08x (%d)\n", result, result);
	}

	// 2
	RecvLength = 256;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("I2C Read Memory (cmd=0xA1) %d byte(s) with Dummy=1, #ofAddr=1\n", RecvLength);
	}

	result = I2C_Read_Memory(ScardHandle[CurrentReader], 
					0xA1,
					0x00,
					RecvBuffer,
					&RecvLength,
					0x01,
					0x01);

	if(result == SCARD_S_SUCCESS)
	{

		if(MessageLevel >= SHOW_DATA)
		{
			printf(     "       Recv Length = %d byte(s)\n", RecvLength);
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}

	}
	else
	{
		printf("I2C Read Memory : 0x%08x (%d)\n", result, result);
	}

	// 3
	RecvLength = 256;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("I2C Read Memory (cmd=0xA1) %d byte(s) with Dummy=0, #ofAddr=2\n", RecvLength);
	}

	result = I2C_Read_Memory(ScardHandle[CurrentReader], 
					0xA1,
					0x00,
					RecvBuffer,
					&RecvLength,
					0x00,
					0x02);

	if(result == SCARD_S_SUCCESS)
	{

		if(MessageLevel >= SHOW_DATA)
		{
			printf(     "       Recv Length = %d byte(s)\n", RecvLength);
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}

	}
	else
	{
		printf("I2C Read Memory : 0x%08x (%d)\n", result, result);
	}

	// 4
	RecvLength = 256;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("I2C Read Memory (cmd=0xA1) %d byte(s) with Dummy=0, #ofAddr=1\n", RecvLength);
	}

	result = I2C_Read_Memory(ScardHandle[CurrentReader], 
					0xA1,
					0x00,
					RecvBuffer,
					&RecvLength,
					0x00,
					0x01);

	if(result == SCARD_S_SUCCESS)
	{

		if(MessageLevel >= SHOW_DATA)
		{
			printf(     "       Recv Length = %d byte(s)\n", RecvLength);
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}

	}
	else
	{
		printf("I2C Read Memory : 0x%08x (%d)\n", result, result);
	}
	
	if(!Disconnect())
	{
		printf("Test_I2C_Read - Fail - \n");
		printf("	<%d> Disconnect Fail\n");
		return 0;
	}

	return 1;
}


int Test_I2C_Write()
{
	long result;
	int i;
	
	if(!Connect())
	{
		printf("Test_I2C_Write - Fail - \n");
		printf("	<%d> Connect Fail : Loop = %d\n");
		return 0;
	}

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("I2C Write Memory (cmd=0xA0) 256 bytes with #ofAddr=1\n");
	}

	for(i = 0; i < 256; ++i)
	{
		SendBuffer[i] = i;
	}

	if(MessageLevel >= SHOW_DATA)
	{
		PrintBuffer("	    Send : ", SendBuffer, 256);
	}

	result = I2C_Write_Memory(ScardHandle[CurrentReader], 
					0xA0,
					0x00,
					SendBuffer,
					256,
					0x01);

	if(result != SCARD_S_SUCCESS)
	{
		printf("I2C Write Memory : 0x%08x (%d)\n", result, result);
	}

	if(!Disconnect())
	{
		printf("Test_I2C_Write - Fail - \n");
		printf("	<%d> Disconnect Fail\n");
		return 0;
	}

	return 1;
}

int 
main(LPTSTR cmdline)
{
	int loop1, loop2, loop3, sleeptime, repeat, i, memkind;
	WCHAR temp[40], *p;
	int select;
	int num, helpnum;
    	
	select = 0;
	loop1 = 1;
	loop2 = 1;
	loop3 = 1;
	sleeptime = 0;
	repeat = 1;
	MessageLevel = 3;
	memkind = 0;
	CurrentReader = 0;

    if(Init())
	{
		p = cmdline;
		swscanf(p, L"%s", temp);

		if(wcscmp(temp, L"-h") == 0)
		{
			helpnum = 1;
			p = p + wcslen(temp) + 1;
			num = swscanf(p, L"%s %d", temp, &CurrentReader);

			if(wcscmp(temp, L"-m") == 0)
			{
				helpnum++;
				p = p + wcslen(temp) + 1;
				select = 1;
				printf("Argument : \n");
				printf("           [-h] CurrentReader MemoryCardType Repeat MessageLevel\n");
				printf("\n");
				printf("MemoryCardType : 0 - SLE4442\n");
				printf("                 1 - SLE4428\n");
				//printf("                 2 - SLE5536");
				printf("                 3 - I2C_Read\n");
				printf("                 4 - I2C_Write\n");
				printf("MessageLevel : 0 - no message\n");
				printf("               1 - show loop\n");
				printf("               2 - show action\n");
				printf("               3 - show data\n");
			}
			else
			{
				printf("Argument : \n");
				printf("           [-h] CurrentReader Test_Part1_Loop Test_Part2_Loop Test_Part3_Loop SleepTime Repeat MessageLevel\n");
				printf("\n");
				printf("SleepTime : thee time to starting next testing, in second\n");
				printf("MessageLevel : 0 - no message\n");
				printf("               1 - show loop\n");
				printf("               2 - show action\n");
				printf("               3 - show data\n");
				wprintf(L"Get CommandLine : %s\n", cmdline);
			}

			if(num < helpnum)
			{	// just help
				return 0;
			}
			

		}
		else if(wcscmp(temp, L"-m") == 0)
		{
			p = p + wcslen(temp) + 1;
			select = 1;
		}
		

		if(select == 1)
		{
			swscanf(p, L"%d %d %d %d", 
					&CurrentReader, &memkind, &repeat, &MessageLevel);

			printf("CurrentReader = %d, MemoryCardType = %d, Repeat = %d, MessageLevel = %d\n", CurrentReader, memkind, repeat, MessageLevel);
		}
		else
		{
			swscanf(p, L"%d %d %d %d %d %d %d", 
					&CurrentReader, &loop1, &loop2, &loop3, &sleeptime, &repeat, &MessageLevel);

			printf("CurrentReader = %d, loop1 = %d, loop2 = %d, loop3 = %d, sleeptime = %d, repeat = %d, MessageLevel = %d\n", 
				CurrentReader, loop1, loop2, loop3, sleeptime, repeat, MessageLevel);
		}
			

		
		if(CurrentReader > (int)ReadersNum)
		{
			printf("Select Out of Range\n");
			return -1;
		}
		
		wprintf(L"%s Selected\n", ScardReaderState[CurrentReader].szReader);

		printf("Start Processing\n");

		if(select == 0)
		{

			for(i = 0; i < repeat; ++i)
			{
				if(!Test_Part_1(loop1, MessageLevel, repeat))
					return 0;

				if(!Test_Part_2(loop2, MessageLevel, repeat))
					return 0;

				if(!Test_Part_3(loop3, MessageLevel, repeat))
					return 0;

				Sleep(sleeptime * 1000);
			}
		}
		else if(select == 1)
		{
			for(i = 0; i < repeat; ++i)
			{
				if(memkind == 0)
				{	// 4442
					Test_SLE4442();
				}
				else if(memkind == 1)
				{	// 4428
					Test_SLE4428();
				}
				else if(memkind == 3)
				{
					printf("<%d> Test_I2C_Read loop = (%d/%d)\n", i, i, repeat);
					Test_I2C_Read();
				}
				else if(memkind == 4)
				{
					printf("<%d> Test_I2C_Write loop = (%d/%d)\n", i, i, repeat);
					Test_I2C_Write();
				}

			}
		}

		printf("End Processing\n");
	}

	return 0;
}


int WINAPI WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR     lpCmdLine,
                     int       nCmdShow)
{
	// Current Reader, Part1_Loop, Part2_Loop, Part3_Loop, sleeptime, repeat, MessageLevel

	main(lpCmdLine);
	return 0;
}